home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 12 - 1996 / 12.07 Jul 96 / CGIs in Lisp < prev    next >
Encoding:
Text File  |  1996-06-14  |  12.7 KB  |  371 lines  |  [TEXT/R*ch]

  1. Listing 1: 
  2. HTML Source of Figure 1
  3.  
  4. The dictionary lookup form
  5.  
  6. All the cosmetic and informative stuff at the beginning of the page.
  7. <TITLE>web-generic-ds</TITLE>
  8. <TABLE CELLPADDING=3 WIDTH="100%">
  9. <TR>
  10.   <TD ALIGN=LEFT>
  11.       <img ALIGN=middle src="http://161.142.8.195/wSambre-us/ALEX/Gifs/wAlex-vert.GIF" WIDTH=25>
  12.       <img ALIGN=middle src="http://161.142.8.195/wSambre-us/ALEX/Gifs/wAlexVLogo.GIF">
  13.   </TD>
  14.   <TD ALIGN=LEFT>
  15. <H1><FONT SIZE=+7>GENERIC</FONT><BR> dictionary web service</H1>
  16.  </TD>
  17. </TR>
  18. </TABLE>
  19.  
  20. The form definition starts here.
  21. <FORM ACTION="http://161.142.8.195/wSambre-us/ALEX/wAlex.acgi" METHOD=Post>
  22.  
  23. <TABLE border UNITS=PIXELS CELLPADDING=2 WIDTH="100%">
  24. <TR>
  25.   <TD>
  26.   <P>To look up for a word fill the text field below and click in the button "Submit". 
  27. You can search by prefixes by adding the character "*" at the end of the entry.<BR>
  28.   </TD></TR>
  29. <TR>
  30.   <TD ALIGN=CENTER>Entry to look up <INPUT TYPE="text" NAME="Entry" VALUE="" MAXLENGTH=150>
  31. in 
  32. <SELECT NAME="DictID">
  33. <OPTION VALUE="2">Français-Malais
  34. <OPTION VALUE="3">English-Malay
  35. <OPTION VALUE="1">informatique Français-Anglais-Malais
  36. </SELECT>
  37.   </TD></TR>
  38. </TABLE>
  39.  
  40. The Submit button is defined here.
  41. <P><CENTER><INPUT TYPE="Submit" VALUE="Look up"></CENTER>
  42.  
  43. One hidden item giving the name of the form we are in.
  44. <INPUT TYPE=HIDDEN NAME="FormName" VALUE="web-generic-ds.html">
  45. The form definition ends here.
  46. </FORM>
  47.  
  48. Some links to specific dictionary forms are presented here.
  49. <HR>
  50. Or if you prefer, you can go to specific form for each of these dictionaries. 
  51. These forms allows filtering. <BR>
  52. <A HREF="http://161.142.8.195/wSambre-us/ALEX/Forms/web-FEM-ds.html">Français-Malais</A> -
  53. <A HREF="http://161.142.8.195/wSambre-us/ALEX/Forms/web-EM-ds.html">English-Malay</A> -
  54. <A HREF="http://161.142.8.195/wSambre-us/ALEX/Forms/web-FEMterm-ds.html">informatique Français-Anglais-Malais</A> 
  55.  
  56. The signature ends the page.
  57. <P><IMG ALIGN = MIDDLE src="http://161.142.8.195/wSambre-us/GIFgeneral/line.GIF"></br>
  58. <FONT SIZE = 1> Last revision 24/11/95 - ALEXv1.84 - wALEXv0.8  <IMG SRC="http://161.142.8.195/wSambre-us/ALEX/Gifs/yellow-diamond.GIF"> 
  59. <A HREF="http://161.142.8.195/wSambre-us/STAFF/ML-us.html">mathieu lafourcade</A> -
  60. <A HREF="http://imag.fr/IMAG/GETA.html">GETA</A>-<A HREF="http://imag.fr/">IMAG</A> | 
  61. <A HREF="http://www.cs.usm.my/">csUSM</A>-<A>UTMK</A> <IMG SRC="http://161.142.8.195/wSambre-us/ALEX/Gifs/yellow-diamond.GIF"> 
  62.  Thanks to: Jon Wiederspan for CGI, all the FEM staff
  63. for the dictionaries, USM dan UTMK, IMAG and GETA, and every person who gave me some feedback.
  64. </FONT><P>
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75.  
  76.  
  77.  
  78.  
  79. Listing 2: 
  80. wAlex.acgi 1/3 (MCL Application)
  81.  
  82. Decoding POST arguments
  83. (defun create-keywords-from-args (args)
  84. ;; segment the string with ‘&’ as a separator
  85.  (let ((mylist (geta-strings::list-words args "&"))
  86.         pair
  87.         result)
  88. ;; for each part, segment with ‘=‘ as a separator and construct the result
  89.   (dolist (lv-pair mylist)
  90.     (setf pair (geta-strings::list-words lv-pair "="))
  91.     (push (second pair) result)
  92.     (push
  93.      (read-from-string 
  94.       (concatenate 'string ":" (first pair))) result)
  95.       )
  96.     result))
  97.  
  98. This list will be simply used as a list of arguments for a function accepting all the variables defined in the HTML form as keys.  Hence, we rely on the standard Lisp binding mechanism to bind each value to its variable.  For our purpose, we ask the appropriate dictionary for an HTML version of the entry structure.
  99. Listing 3: 
  100. wAlex.acgi 2/3 (MCL Application)
  101.  
  102. Getting the corresponding entry
  103. (defun get-walex-entry  (&key dictid 
  104.                          dicttype
  105.                          formname 
  106.                          entry
  107.                          &allow-other-keys)
  108. ;; Now, we can directly use each variable to query our dictionary
  109.   (let ((dict (get-dictionary dictid dicttype)))
  110.     (findAndTransmuteItem 
  111.       dict
  112.       entry :output-format :html-1))
  113.   )
  114. Replying
  115. MacHTTP expects the Apple event reply’s direct parameter to contain an HTTP/1.0 header and HTML text that will be transmitted to the client.  Hence, we have to construct an appropriate answer.  The HTML/1.0 header will be built as a global variable:
  116.  
  117. ;; Define the http 1.0 header (beware of crlf)
  118. (defvar *crlf* 
  119.   (format nil "~A~A" #\Linefeed #\Newline))
  120. (defvar *http-10-header* 
  121.   (format nil "HTTP/1.0 200 OK ~A~
  122.                Server: MacHTTP ~A~
  123.                MIME-Version: 1.0 ~A~
  124.                Content-type: text/html ~A~A" 
  125.           *crlf* *crlf* *crlf* *crlf* *crlf*))
  126.  
  127. The reply itself will be returned by the findAndTransmuteItem function.  Hence, we just have to put the header and answer in the Apple event reply’s direct parameter with the ae-put-parameter-char function.
  128.  
  129. Listing 4: 
  130. wAlex.acgi 3/3 (MCL Application)
  131.  
  132. Defining and installing the Apple event handler
  133.  
  134. (defmethod my-ae-handler ((a application) 
  135.                           theAppleEvent
  136.                           reply
  137.                           handlerRefcon)
  138. ;; We don’t use the handlerRefcon argument
  139.   (declare (ignore handlerRefcon))
  140. ;; Just get the post parameter, decode it, handle it and reply
  141.   (let* ((post-args 
  142.            (create-keywords-from-args
  143.              (ae-get-parameter-char theAppleEvent 
  144.                                     :|post| t)))
  145.          (the-answer 
  146.           (apply #'get-walex-entry post-args)))
  147. ;; Build the reply and put it into the Apple event reply’s direct parameter
  148.     (ae-put-parameter-char reply #$keyDirectObject 
  149.                            (format nil "~A ~A"
  150.                                    *http-10-header*
  151.                                    the-answer))
  152. ))
  153. (install-appleevent-handler :|WWWΩ| :|sdoc| #'my-ae-handler)
  154.  
  155.  
  156.  
  157.  
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164.  
  165.  
  166.  
  167.  
  168.  
  169.  
  170.  
  171. Listing 5: 
  172. wAlex.acgi (AppleScript Applet)
  173.  
  174. Properties and CGI entry point
  175.  
  176. -- This code comes from Jon Wiederspan and has been modified to fit our purposes.
  177. -- Some properties are defined for making it easier to read.
  178. property crlf : (ASCII character 13) & (ASCII character 10)
  179. property http_10_header : "HTTP/1.0 200 OK" & crlf & "Server: MacHTTP" & crlf & "MIME-Version: 1.0" & crlf & "Content-type: text/html" & crlf & crlf
  180.  
  181. property theApp : application "Alex"
  182.  
  183. -- The main entry of our script.
  184. on «event WWWΩsdoc» path_args ¬
  185.     given «class kfor»:http_search_args, «class post»:post_args, «class meth»:method, «class addr»:client_address, «class user»:username, «class pass»:|password|, «class frmu»:from_user, «class svnm»:server_name, «class svpt»:server_port, «class scnm»:script_name, «class ctyp»:content_type
  186.  
  187. -- Decode the Post arguments.
  188.     try
  189.         -- Tokenizing our arguments means creating a list (or arguments) form a string
  190.         set tokenized_pa to tokenize post_args with delimiters {"&"}
  191.  
  192. -- Save the original AppleScript text item delimiters.
  193.         set oldDelim to AppleScript's text item delimiters
  194.  
  195. -- Use “=“ to delimit the pairs.
  196.         set AppleScript's text item delimiters to {"="}
  197.  
  198. -- Retrieve our arguments (it is positional and thus not very nice).
  199.         set theEntry to (Decode URL 
  200.             (dePlus (last text item of item 1 of tokenized_pa)))
  201.         set theBaseID to (Decode URL 
  202.             (dePlus (last text item of item 3 of tokenized_pa)))
  203.  
  204. -- Restore the original AppleScript text item delimiters.
  205.         set AppleScript's text item delimiters to oldDelim
  206.  
  207. -- Returns the result (we don’t use theFrom for simplicity)
  208.         return http_10_header & 
  209.             getAlexEntryWithID(theBaseID, theEntry, post_args)
  210.  
  211. -- Error handling (not detailed).
  212.     on error msg number num 
  213.         …
  214.     end try
  215. end «event WWWΩsdoc»
  216.  
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223.  
  224.  
  225.  
  226.  
  227.  
  228.  
  229.  
  230.  
  231.  
  232.  
  233. Listing 6: 
  234. ASPI
  235.  
  236. getAlexEntryWithID
  237. -- Get the data in the HTML format with the id of the base.
  238. on getAlexEntryWithID(id, entry, args)
  239.     tell TheApp
  240.         do script ("(get-alex-item (alex::base 
  241.             (alex::get-dict-handler \"" & id & 
  242.             "\"  :id)) " & "\"" & entry & "\"" & 
  243.             " :output-format :html-1 & :args & "\"" args & "\")")
  244.     end tell
  245. end getAlexEntryWithID
  246.  
  247.  
  248.  
  249.  
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256.  
  257.  
  258.  
  259.  
  260.  
  261. Listing 7: 
  262. Other ASPI Useful for ALEX
  263.  
  264. openAlexDictionary
  265.  
  266. -- Open a base from a given filename. Return an index dictionary or 0 in case of error.
  267. on openAlexDictionary(filename)
  268.     tell theApp
  269.         return do script ¬
  270.             ("(alex::open-object :alex-base :return-index t :file 
  271.                 (pathname \"" & filename & "\"))")
  272.     end tell
  273. end openAlexDictionary
  274.  
  275. getAlexDictionaryName
  276. -- Return the dictionary name based on the dictionary id.
  277. on getAlexDictionaryName(id)
  278.     tell theApp
  279.         return do script ("(alex:name (alex::base 
  280.             (alex::get-dict-handler \"" & id & "\"  :id)))")
  281.     end tell
  282. end getAlexDictionaryName
  283.  
  284.  
  285. deleteAlexEntryWithID
  286. -- Deletes an entry (if defined) based on the dictionary id.
  287. on deleteAlexEntryWithID(id, entry)
  288.     tell theApp
  289.         do script ("(delete-item (alex::base 
  290.             (alex::get-dict-handler \"" & id & "\"  :id)) :key " 
  291.             & "\"" & entry & "\"" & ")")
  292.     end tell
  293. end deleteAlexEntryWithID
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301.  
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308. Listing 8: 
  309. Two CLOS Headers for Plain Text and HTML Formatting
  310.  
  311. transmute-entry 
  312. First method for of text output (code not detailed).
  313. (defmethod transmute-entry    (entry
  314.                                  (entry-type (eql :en-entry))
  315.                                  (output-format (eql :text)) )
  316.     …)
  317.  
  318. Second method for one kind of HTML output (code not detailed).
  319. (defmethod transmute-entry    (entry
  320.                                  (entry-type (eql :en-entry))
  321.                                  (output-format (eql :html-1)) )
  322.     …)
  323. Listing 9: 
  324. High-level Format of ALEX Items
  325.  
  326. High-level format for “apple”
  327.  
  328. The high level format of ALEX is a (kind of) property list. The first item is always the type of the entry. The rest of the structure is made of an open list composed of a type and one or several string values.
  329. (:EM-ENTRY (:ENTRY "apple") (:C "n") (:N "1") (:G "(tree)") (:ME "pokok epal") (:N "2") (:G "(fruit)") (:ME "(buah) epal") (:P "an apple") (:P "the apple") (:P "bad apple") (:P "rotten apple") (:MPE "orang yg tdk baik") (:P "an apple for the teacher") (:MPE "sogokan") (:MPE "tumbuk rusuk") (:P "an apple of discord") (:P "the apple of discord") (:MPE "punca perselisihan") (:MPE "punca pergaduhan") (:MPE "punca perkelahian") (:P "the apple of o's eye") (:MPE "kesayangan sso") (:MPE "buah hati."))
  330. Requested output format
  331. The code produced by ALEX for the entry “apple” is given in listing 10 (the code has been slightly edited for readability).  Besides the cosmetic features of the page, the most interesting part of the listing is the handling of the “previous” and “next” entries.
  332. Listing 10: 
  333. Source of Figure 2
  334.  
  335. HTML “apple”
  336.  
  337. Beginning of the header of the page and control part for access to the previous and next entries.
  338. <TABLE CELLPADDING=0 WIDTH="100%"><TD><IMG SRC="http://161.142.8.195/wSambre-us/ALEX/Gifs/walex-vert.GIF" width=10> <IMG ALIGN=Bottom SRC="http://161.142.8.195/wSambre-us/ALEX/Gifs/stack.GIF"><b><FONT SIZE = +6> apple </FONT></B> <TD ALIGN=Right><TABLE border=0> 
  339.  
  340. The left arrow and the previous word. Here (and only here) the GET method is used in the urls (notice the ? character).
  341. <TD VALIGN=CENTER>
  342. <A HREF="http://161.142.8.195/wSambre-us/ALEX/wALEXScript.acgi?ENTRY=applause&FORMNAME=web-generic-ds.html&DICTID=3"><IMG SRC="http://161.142.8.195/wSambre-us/ALEX/Gifs/left-arrow.GIF" BORDER=0></A></TD>
  343. <TD VALIGN=CENTER><A HREF="http://161.142.8.195/wSambre-us/ALEX/wALEXScript.acgi?ENTRY=applause&FORMNAME=web-generic-ds.html&DICTID=3"> applause</A>
  344. </TD>
  345.  
  346. The link back to the form.
  347. <TD VALIGN=CENTER> | <A HREF="http://161.142.8.195/wSambre-us/ALEX/Forms/web-generic-ds.html">back to form</A> | </TD> 
  348.  
  349. The right arrow and the next word.
  350. <TD VALIGN=CENTER><A HREF="http://161.142.8.195/wSambre-us/ALEX/wALEXScript.acgi?ENTRY=apple+brandy&FORMNAME=web-generic-ds.html&DICTID=3">apple brandy</A></TD> 
  351. <TD VALIGN=CENTER><A HREF="http://161.142.8.195/wSambre-us/ALEX/wALEXScript.acgi?ENTRY=apple+brandy&FORMNAME=web-generic-ds.html&DICTID=3"><IMG SRC="http://161.142.8.195/wSambre-us/ALEX/Gifs/right-arrow.GIF" BORDER=0></A></TD></TABLE></TABLE>
  352.  
  353. The informative part of this page.
  354. <HR SIZE=4><DL COMPACT>
  355. <DT><B>apple</B> 
  356. <DD><I>n</I><IMG HSPACE=8 SRC="http://161.142.8.195/wSambre-us/ALEX/Gifs/space.GIF"> <IMG HSPACE=6 SRC="http://161.142.8.195/wSambre-us/ALEX/Gifs/red-diamond.GIF">
  357. <B>1</B> -  (tree); <IMG SRC="http://161.142.8.195/wSambre-us/ALEX/Gifs/cyan-diamond.GIF"> pokok epal <IMG HSPACE=6 SRC="http://161.142.8.195/wSambre-us/ALEX/Gifs/red-diamond.GIF">
  358. <B>2</B> - (fruit); <IMG SRC="http://161.142.8.195/wSambre-us/ALEX/Gifs/cyan-diamond.GIF"> (buah) epal  rotten apple, bad apple, the apple, an apple; <IMG SRC="http://161.142.8.195/wSambre-us/ALEX/Gifs/cyan-diamond.GIF"> orang yg tdk baik  an apple for the teacher; <IMG SRC="http://161.142.8.195/wSambre-us/ALEX/Gifs/cyan-diamond.GIF"> tumbuk rusuk, sogokan  the apple of discord, an apple of discord; <IMG SRC="http://161.142.8.195/wSambre-us/ALEX/Gifs/cyan-diamond.GIF"> punca perkelahian, punca pergaduhan, punca perselisihan  the apple of o's eye; <IMG SRC="http://161.142.8.195/wSambre-us/ALEX/Gifs/cyan-diamond.GIF"> buah hati., kesayangan sso.</DL>
  359.  
  360. Information to remind the user in which dictionary he is looking.
  361. <HR><FONT SIZE=1>from English-Malay</FONT>
  362.  
  363.  
  364.  
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.